package com.haohan.cloud.scm.saleb.core.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haohan.cloud.scm.api.bill.req.BillInfoFeignReq;
import com.haohan.cloud.scm.api.constant.ScmCacheNameConstant;
import com.haohan.cloud.scm.api.constant.enums.common.UseStatusEnum;
import com.haohan.cloud.scm.api.constant.enums.opc.YesNoEnum;
import com.haohan.cloud.scm.api.constant.enums.saleb.PayPeriodEnum;
import com.haohan.cloud.scm.api.manage.entity.Merchant;
import com.haohan.cloud.scm.api.manage.entity.UPassport;
import com.haohan.cloud.scm.api.saleb.entity.BuyOrder;
import com.haohan.cloud.scm.api.saleb.entity.Buyer;
import com.haohan.cloud.scm.api.saleb.req.buyer.BuyerEditReq;
import com.haohan.cloud.scm.api.saleb.req.buyer.BuyerQueryReq;
import com.haohan.cloud.scm.api.saleb.vo.BuyerPayVO;
import com.haohan.cloud.scm.api.saleb.vo.BuyerVO;
import com.haohan.cloud.scm.common.tools.exception.ErrorDataException;
import com.haohan.cloud.scm.common.tools.thread.ScmGlobalThreadPool;
import com.haohan.cloud.scm.saleb.core.BuyerCoreService;
import com.haohan.cloud.scm.saleb.service.BuyOrderService;
import com.haohan.cloud.scm.saleb.service.BuyerService;
import com.haohan.cloud.scm.saleb.utils.ScmBuyerTrans;
import com.haohan.cloud.scm.saleb.utils.ScmSaleBUtils;
import com.pig4cloud.pigx.admin.api.dto.UserDTO;
import com.pig4cloud.pigx.admin.api.dto.UserInfo;
import com.pig4cloud.pigx.admin.api.entity.SysDept;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author dy
 * @date 2019/9/20
 */
@Service
@Slf4j
@AllArgsConstructor
public class BuyerCoreServiceImpl implements BuyerCoreService {
    private final BuyerService buyerService;
    private final ScmSaleBUtils scmSaleBUtils;
    private final BuyOrderService buyOrderService;

    /**
     * 查询采购商 当前时间未结算账单数
     *
     * @param pmId    该参数废弃
     * @param buyerId
     * @return
     */
    @Override
    public Integer countBuyerBill(String pmId, String buyerId) {
        Buyer buyer = buyerService.list(Wrappers.<Buyer>query().lambda()
                .eq(Buyer::getId, buyerId)
                .eq(Buyer::getStatus, UseStatusEnum.enabled)
        ).stream().findFirst().orElse(null);
        if (null == buyer) {
            return null;
        }
        if (buyer.getNeedConfirmation() == YesNoEnum.no) {
            return 0;
        }
        // 账期日计算
        PayPeriodEnum payPeriod = buyer.getPayPeriod();
        payPeriod = (null == payPeriod) ? PayPeriodEnum.day : payPeriod;
        String payDay = buyer.getPayDay();
        payDay = StrUtil.isBlank(payDay) ? "1" : payDay;
        int day = Integer.parseInt(payDay);
        int max;
        LocalDate endDate = LocalDate.now();

        switch (payPeriod) {
            case month:
                max = endDate.getDayOfMonth();
                day = (0 <= day && day <= max) ? day : 1;
                endDate = endDate.withDayOfMonth(day);
                break;
            case week:
                max = 7;
                day = (0 <= day && day <= max) ? day : 1;
                endDate = endDate.with(TemporalAdjusters.previous(DayOfWeek.of(day)));
                break;
            case day:
                endDate = endDate.minusDays(day);
                break;
            default:
        }
        // endDate前, 采购商未结算账单数
        BillInfoFeignReq req = new BillInfoFeignReq();
        req.setPmId(pmId);
        req.setCustomerId(buyerId);
        req.setSettlementStatus(YesNoEnum.no);
        req.setEndDate(endDate);
        return scmSaleBUtils.countReceivableBill(req);
    }


    /**
     * 根据uid查询
     * 查询不到时新增采购商
     * 创建采购商,若无对应商家也创建
     * (salec用户转采购商, 默认无saleb小程序、管理后台登陆功能)
     *
     * @param query passportId必须
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Buyer fetchBuyerByUidWithAdd(Buyer query) {
        // 根据uid查询
        Buyer exist = buyerService.fetchByUid(query.getPassportId());
        if (null != exist) {
            return exist;
        }
        // 根据手机号判断 有重复时修改uid
        exist = buyerService.fetchByTelephone(query.getTelephone());
        if (null != exist) {
            Buyer update = new Buyer();
            update.setId(exist.getId());
            update.setPassportId(query.getPassportId());
            buyerService.updateById(update);
            return exist;
        }
        // 商家根据名称查询
        String merchantName = StrUtil.isEmpty(query.getMerchantName()) ? query.getBuyerName() : query.getMerchantName();
        Merchant merchant = scmSaleBUtils.fetchMerchantByName(merchantName);
        if (null == merchant) {
            // 创建商家
            merchant = ScmBuyerTrans.initMerchant(query, merchantName);
            merchant = scmSaleBUtils.createMerchantWithPlatform(merchant);
        }
        query.setPmId(merchant.getParentId());
        query.setMerchantId(merchant.getId());
        query.setMerchantName(merchantName);
        buyerService.save(query);
        return query;
    }

    /**
     * 客户联系人创建采购商(用于登录saleb小程序)
     * (默认无管理后台登陆功能)
     *
     * @param buyer
     * @return
     */
    @Override
    public Buyer createBuyerByCustomer(Buyer buyer) {
        // 根据手机号或名称判断重复
        Buyer exist = buyerService.fetchByTelephone(buyer.getTelephone());
        if (null == exist) {
            exist = buyerService.fetchByName(buyer.getBuyerName());
        }
        if (null != exist) {
            buyer.setId(exist.getId());
            buyer.setUserId(exist.getUserId());
            buyerService.updateById(buyer);
        } else {
            buyerService.save(buyer);
        }
        return buyer;
    }

    @Override
    public IPage<BuyerVO> findPage(Page<Buyer> page, BuyerQueryReq req) {
        IPage<Buyer> supplierPage = buyerService.page(page, Wrappers.query(req.transTo())
                .orderByAsc("sort + 0")
                .orderByDesc("create_date")
                .lambda()
                .like(StrUtil.isNotEmpty(req.getMerchantName()), Buyer::getMerchantName, req.getMerchantName())
                .like(StrUtil.isNotEmpty(req.getBuyerName()), Buyer::getBuyerName, req.getBuyerName())
                .like(StrUtil.isNotEmpty(req.getShortName()), Buyer::getShortName, req.getShortName())
                .like(StrUtil.isNotEmpty(req.getContact()), Buyer::getContact, req.getContact())
                .like(StrUtil.isNotEmpty(req.getTelephone()), Buyer::getTelephone, req.getTelephone())
                .like(StrUtil.isNotEmpty(req.getAddress()), Buyer::getAddress, req.getAddress())
                .like(StrUtil.isNotEmpty(req.getArea()), Buyer::getArea, req.getArea())
        );
        IPage<BuyerVO> result = new Page<>(supplierPage.getCurrent(), supplierPage.getSize(), supplierPage.getTotal());
        result.setRecords(supplierPage.getRecords().stream()
                .map(BuyerVO::new)
                .collect(Collectors.toList())
        );
        return result;
    }

    @Override
    public BuyerVO fetchInfoWithRole(String buyerId) {
        Buyer buyer = buyerService.getById(buyerId);
        if (null == buyer) {
            throw new ErrorDataException("采购商有误");
        }
        BuyerVO result = new BuyerVO(buyer);
        // 角色、部门
        UserInfo userInfo = scmSaleBUtils.fetchUserById(buyer.getUserId());
        if (null != userInfo) {
            List<Integer> list = new ArrayList<>(userInfo.getRoles().length);
            list.addAll(Arrays.asList(userInfo.getRoles()));
            result.setRoleList(list);
            String deptId = null;
            if (userInfo.getSysUser() != null && userInfo.getSysUser().getDeptId() != null) {
                deptId = userInfo.getSysUser().getDeptId().toString();
            }
            SysDept dept = scmSaleBUtils.fetchDeptById(deptId);
            if (dept != null) {
                result.setDeptName(dept.getName());
                result.setDeptId(deptId);
            }
        } else {
            result.setRoleList(new ArrayList<>(0));
        }
        return result;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addBuyer(BuyerEditReq req) {
        //  验证手机号、名称是否重复
        checkNameAndTelephone(req.getBuyerName(), req.getTelephone());
        Buyer buyer = req.transTo();
        // 商家
        merchantHandle(buyer);
        // 新增平台用户 角色、部门
        SysDept dept = scmSaleBUtils.fetchDeptById(req.getDeptId());
        UserDTO user = fetchUserDTO(buyer, dept, req.getRoleIds());
        user = scmSaleBUtils.addUser(user);
        buyer.setUserId(user.getUserId().toString());
        buyer.setPassportId(user.getOscId());
        buyer.setId(null);
        return buyerService.save(buyer);
    }

    private UserDTO fetchUserDTO(Buyer buyer, SysDept dept, String roleIds) {
        // 角色、user
        List<Integer> roleList = new ArrayList<>(10);
        if (StrUtil.isNotEmpty(roleIds)) {
            String[] roleArray = StrUtil.split(roleIds, StrUtil.COMMA);
            for (String s : roleArray) {
                roleList.add(Integer.valueOf(s));
            }
        }
        UserDTO user = new UserDTO();
        user.setRole(roleList);
        if (null != dept) {
            user.setDeptId(dept.getDeptId());
        }
        if (StrUtil.isNotEmpty(buyer.getUserId())) {
            user.setUserId(Integer.valueOf(buyer.getUserId()));
        }
        user.setUsername(buyer.getBuyerName());
        // 密码默认手机号
        user.setPassword(buyer.getTelephone());
        user.setPhone(buyer.getTelephone());
        // 默认user不可登录后台
        user.setLockFlag(CommonConstants.STATUS_LOCK);
        return user;
    }

    private void merchantHandle(Buyer buyer) {
        Merchant merchant = scmSaleBUtils.fetchMerchantById(buyer.getMerchantId());
        if (null == merchant) {
            throw new ErrorDataException("采购商家有误");
        }
        buyer.setMerchantName(merchant.getMerchantName());
        // 设置平台商家, 采购商使用原系统时需要
        Merchant pm = scmSaleBUtils.fetchPlatformMerchant();
        buyer.setPmId(pm.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean modifyBuyer(BuyerEditReq req) {
        Buyer exist = buyerService.getById(req.getId());
        if (null == exist) {
            throw new ErrorDataException("采购商有误");
        }
        boolean updateNameFlag = !StrUtil.equals(req.getBuyerName(), exist.getBuyerName());
        String name = updateNameFlag ? req.getBuyerName() : "";
        String telephone = StrUtil.equals(req.getTelephone(), exist.getTelephone()) ? "" : req.getTelephone();
        // 验证 修改的  手机号、名称是否重复
        checkNameAndTelephone(name, telephone);
        Buyer buyer = req.transTo();
        // 商家
        merchantHandle(buyer);
        SysDept dept = scmSaleBUtils.fetchDeptById(req.getDeptId());
        UserDTO user = fetchUserDTO(buyer, dept, req.getRoleIds());
        if (StrUtil.isNotEmpty(exist.getUserId())) {
            // 不修改密码
            user.setPassword(null);
            user.setUserId(Integer.valueOf(exist.getUserId()));
            if (!scmSaleBUtils.updateUser(user)) {
                return false;
            }
            // 若无uid需新增 修改手机号、名称时更新
            if (StrUtil.isEmpty(exist.getPassportId()) || StrUtil.isNotEmpty(telephone) || updateNameFlag) {
                UPassport passport = new UPassport();
                passport.setLoginName(buyer.getBuyerName());
                passport.setTelephone(buyer.getTelephone());
                passport.setAvatar("");
                buyer.setPassportId(scmSaleBUtils.addUPassPort(passport).getId());
            }
        } else {
            user = scmSaleBUtils.addUser(user);
            buyer.setUserId(user.getUserId().toString());
            buyer.setPassportId(user.getOscId());
        }
        boolean flag = buyerService.updateById(buyer);
        // 修改名称时 关联表 更新
        if (updateNameFlag) {
            allUpdateBuyerName(exist.getId(), name);
        }
        return flag;
    }

    /**
     * 采购商名称修改 全更新
     *
     * @param buyerId
     * @param buyerName
     */
    private void allUpdateBuyerName(String buyerId, String buyerName) {
        ScmGlobalThreadPool.getExecutor().execute(() -> {
            // 供应订单中
            BuyOrder buyOrder = new BuyOrder();
            buyOrder.setBuyerName(buyerName);
            buyOrderService.update(buyOrder, Wrappers.<BuyOrder>update().lambda()
                    .eq(BuyOrder::getBuyerId, buyerId)
            );
        });
    }

    /**
     * 删除采购商
     *
     * @param buyerId
     * @return
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = ScmCacheNameConstant.WECHAT_BUYER_INFO, allEntries = true),
            @CacheEvict(value = ScmCacheNameConstant.MANAGE_PRICING_MERCHANT_ID, allEntries = true)
    })
    public boolean deleteBuyer(String buyerId) {
        Buyer buyer = buyerService.getById(buyerId);
        if (null == buyer) {
            throw new ErrorDataException("采购商有误");
        }
        // 采购单
        int num = buyOrderService.count(Wrappers.<BuyOrder>query().lambda()
                .eq(BuyOrder::getBuyerId, buyerId)
        );
        if (num > 0) {
            throw new ErrorDataException("该采购商有供应订单存在, 不可删除");
        }
        // 删除用户
        scmSaleBUtils.deleteUser(buyer.getUserId());
        return buyerService.removeById(buyerId);
    }

    @Override
    public boolean updateMerchantName(String merchantId, String merchantName) {
        if (StrUtil.isEmpty(merchantId) || StrUtil.isEmpty(merchantName)) {
            throw new ErrorDataException("缺少参数merchantId、merchantName");
        }
        Buyer update = new Buyer();
        update.setMerchantName(merchantName);
        return buyerService.update(update, Wrappers.<Buyer>query().lambda()
                .eq(Buyer::getMerchantId, merchantId)
        );
    }

    private void checkNameAndTelephone(String buyerName, String telephone) {
        Buyer exist = buyerService.fetchByTelephone(telephone);
        if (null != exist) {
            throw new ErrorDataException("该手机号已存在采购商");
        }
        exist = buyerService.fetchByName(buyerName);
        if (null != exist) {
            throw new ErrorDataException("该名称已存在采购商");
        }
    }

    /**
     * 查询采购商是否需下单支付
     * 默认需要
     *
     * @param buyerId
     * @return
     */
    @Override
    public BuyerPayVO queryBuyerPayInfo(String buyerId) {
        Buyer buyer = buyerService.getById(buyerId);
        // 默认需要
        boolean flag;
        if (null == buyer || buyer.getStatus() != UseStatusEnum.enabled || null == buyer.getNeedPay()) {
            flag = true;
        } else {
            flag = buyer.getNeedPay() == YesNoEnum.yes;
        }
        // todo 若需预付部分 设置预付金额
        return new BuyerPayVO(flag, BigDecimal.ZERO);
    }
}
